#include <QFile>
#include <QDataStream>
#include "dataspecification.h"
#include "spectrumfactory.h"
#include "private/spectrumdatafileprivatedefine.h"
#include "common/dataspecificationutils.h"
#include "common/binaryprocesshelper.h"
#include "common/xmldocument.h"
#include "private/spectrumdatafilecommondefine.h"
#include "common/jsonprocesshelper.h"
#include "crcutil/crcutil.h"
#include "ae/aeampspectrum.h"
#include "ae/aephasespectrum.h"
#include "ae/aepulsespectrum.h"
#include "ae/aewavespectrum.h"
#include "prps/prpsspectrum.h"
#include "prps/prpdspectrum.h"
#include "tev/tevampspectrum.h"
#include "mechanical/mechanicalspectrum.h"
#include "mechanical/mechanicalcoilspectrum.h"
#include "mechanical/mechanicalmotorspectrum.h"
#include "mechanical/mechanicalswitchspectrum.h"
#include "infrared/infraredspectrum.h"
#include "currentamplitude/currentampspectrum.h"
#include "Crypto/QtCrypto.h"
#include <QDebug>

namespace DataSpecificationGW
{
    namespace
    {
        const int DATA_FILE_TAIL_RESERVED_BYTES_CNT = 32;
    }

    class DataSpecificationPrivate
    {
    public:
        SpectrumDataFileHeadPrivate m_stFileHead;
        SpectrumsPrivate m_stSpectrums;
        SpectrumDataFileTailPrivate m_stFileTail;
    };

    DataSpecification::DataSpecification()
        : m_pDataSpecificationPrivate(new DataSpecificationPrivate),
          m_eDataSpecificationVersion(DefaultDataSpecificationVersion)
    {
        SpectrumFactory::registerClass<MechanicalSpectrum>(STR_FILE_NODE_MECHANICAL);
        SpectrumFactory::registerClass<MechanicalCoilSpectrum>(STR_FILE_NODE_MECHANICAL_COIL);
        SpectrumFactory::registerClass<MechanicalMotorSpectrum>(STR_FILE_NODE_MECHANICAL_MOTOR);
        SpectrumFactory::registerClass<MechanicalSwitchSpectrum>(STR_FILE_NODE_MECHANICAL_SWITCH);
        SpectrumFactory::registerClass<AEAmpSpectrum>(STR_FILE_NODE_AE_AMP);
        SpectrumFactory::registerClass<AEPhaseSpectrum>(STR_FILE_NODE_AE_PHASE);
        SpectrumFactory::registerClass<AEPulseSpectrum>(STR_FILE_NODE_AE_PULSE);
        SpectrumFactory::registerClass<AEWaveSpectrum>(STR_FILE_NODE_AE_WAVE);
        SpectrumFactory::registerClass<PRPSSpectrum>(STR_FILE_NODE_PRPS);
        SpectrumFactory::registerClass<PRPDSpectrum>(STR_FILE_NODE_PRPD);
        SpectrumFactory::registerClass<TEVAmpSpectrum>(STR_FILE_NODE_TEV_AMP);
        SpectrumFactory::registerClass<InfraredSpectrum>(STR_FILE_NODE_INFRARED);
        SpectrumFactory::registerClass<CurrentAmpSpectrum>(STR_FILE_NODE_CURRENT_AMP);
    }

    DataSpecification::~DataSpecification()
    {
        clearSpectrums();
    }

    /************************************************
     * 函数名   : addSpectrum
     * 输入参数 :
       Spectrum* pSpectrum: 图谱指针
     * 输出参数 : NULL
     * 返回值   : int
     * 功能     : 添加图谱
     ************************************************/
    int DataSpecification::addSpectrum(Spectrum* pSpectrum)
    {
        int iRet = -1;

        if (NULL == pSpectrum)
        {
            qDebug() << "Spectrum is NULL!";
            return iRet;
        }

        if (m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.end() == std::find(m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.begin(), m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.end(), pSpectrum))
        {
            iRet = m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.size();
            pSpectrum->setDataSpecificationVersion(m_eDataSpecificationVersion);
            m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.push_back(pSpectrum);
            ++m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount;
        }
        else
        {
            // 如果存在不更新？ issue?
            qDebug() << "Spectrum has existed!";
        }

        return iRet;
    }

    /************************************************
     * 函数名   : spectrum
     * 输入参数 :
       const int iIndex: 索引
     * 输出参数 : NULL
     * 返回值   : Spectrum*
     * 功能     : 获取指定位置图谱的指针
     ************************************************/
    Spectrum* DataSpecification::spectrum(const int iIndex)
    {
        if (iIndex < 0 || iIndex > m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.size())
        {
            qDebug() << "DataSpecification::spectrum: index is out of range !";
            return Q_NULLPTR;
        }

        return m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum[iIndex];
    }

    /************************************************
     * 函数名   : spectrum
     * 输入参数 :
       const SpectrumTypeCode eSpectrumCode: 图谱类型编码
     * 输出参数 : NULL
     * 返回值   : Spectrum*
     * 功能     : 获取特定类型的图谱的指针
     ************************************************/
    Spectrum* DataSpecification::spectrum(const SpectrumTypeCode eSpectrumCode)
    {
        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (eSpectrumCode == pSpectrum->spectrumTypeCode())
            {
                return pSpectrum;
            }
        }

        return Q_NULLPTR;
    }

    /************************************************
     * 函数名   : spectrums
     * 输入参数 : NULL
     * 输出参数 : NULL
     * 返回值   : Spectrum*
     * 功能     : 获取所有图谱的指针
     ************************************************/
    std::vector<Spectrum*> DataSpecification::spectrums()
    {
        return m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum;
    }

    /************************************************
     * 函数名   : spectrums
     * 输入参数 :
       const SpectrumTypeCode eSpectrumCode: 图谱类型编码
     * 输出参数 : NULL
     * 返回值   : Spectrum*
     * 功能     : 获取特定类型的图谱的指针
     ************************************************/
    std::vector<Spectrum*> DataSpecification::spectrums(const SpectrumTypeCode eSpectrumCode)
    {
        std::vector<Spectrum*> vecSpectrum;
        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (eSpectrumCode == pSpectrum->spectrumTypeCode())
            {
                vecSpectrum.push_back(pSpectrum);
            }
        }

        return vecSpectrum;
    }

    /************************************************
     * 函数名   : setVersion
     * 输入参数 :
       const QString& qstrVersion: 版本号
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置版本号
     ************************************************/
    void DataSpecification::setVersion(const QString& qstrVersion)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrVersion = qstrVersion;
    }

    /************************************************
     * 函数名   : setStationName
     * 输入参数 :
       const QString& qstrStationName: 站点名称
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置站点名称
     ************************************************/
    void DataSpecification::setStationName(const QString& qstrStationName)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrStationName = qstrStationName;
    }

    /************************************************
     * 函数名   : setStationCode
     * 输入参数 :
       const QString& qstrStationCode: 站点编码
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置站点编码
     ************************************************/
    void DataSpecification::setStationCode(const QString& qstrStationCode)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode = qstrStationCode;
    }

    /************************************************
     * 函数名   : setWeather
     * 输入参数 :
       const Weather eWeather: 天气
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置天气
     ************************************************/
    void DataSpecification::setWeather(const Weather eWeather)
    {
        m_pDataSpecificationPrivate->m_stFileHead.ucWeather = eWeather;
    }

    /************************************************
     * 函数名   : setTemperature
     * 输入参数 :
       const float fTemperature: 温度
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置温度
     ************************************************/
    void DataSpecification::setTemperature(const float fTemperature)
    {
        m_pDataSpecificationPrivate->m_stFileHead.fTemperature = fTemperature;
    }

    /************************************************
     * 函数名   : setHumidity
     * 输入参数 :
       const qint8 cHumidity: 湿度
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置湿度
     ************************************************/
    void DataSpecification::setHumidity(const qint8 cHumidity)
    {
        m_pDataSpecificationPrivate->m_stFileHead.cHumidity = cHumidity;
    }

    /************************************************
     * 函数名   : setInstrumentManufacturer
     * 输入参数 :
       const QString& qstrInstrumentManufacturer: 仪器厂家
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置仪器厂家
     ************************************************/
    void DataSpecification::setInstrumentManufacturer(const QString& qstrInstrumentManufacturer)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer = qstrInstrumentManufacturer;
    }

    /************************************************
     * 函数名   : setInstrumentModel
     * 输入参数 :
       const QString& qstrInstrumentModel: 仪器型号
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置仪器型号
     ************************************************/
    void DataSpecification::setInstrumentModel(const QString& qstrInstrumentModel)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel = qstrInstrumentModel;
    }

    /************************************************
     * 函数名   : setInstrumentVersion
     * 输入参数 :
       const QString& qstrInstrumentVersion: 仪器版本号
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置仪器版本号
     ************************************************/
    void DataSpecification::setInstrumentVersion(const QString& qstrInstrumentVersion)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion = qstrInstrumentVersion;
    }

    /************************************************
     * 函数名   : setInstrumentSerialNumber
     * 输入参数 :
       const QString& qstrInstrumentSerialNumber: 仪器序列号
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置仪器序列号
     ************************************************/
    void DataSpecification::setInstrumentSerialNumber(const QString& qstrInstrumentSerialNumber)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber = qstrInstrumentSerialNumber;
    }

    /************************************************
     * 函数名   : setSystemFrequency
     * 输入参数 :
       const float fSystemFrequency: 系统频率
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置系统频率
     ************************************************/
    void DataSpecification::setSystemFrequency(const float fSystemFrequency)
    {
        m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency = fSystemFrequency;
    }

    /************************************************
     * 函数名   : setCompanyCode
     * 输入参数 :
       const QString& qstrCompanyCode: 公司代码
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置公司代码
     ************************************************/
    void DataSpecification::setCompanyCode(const QString& qstrCompanyCode)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode = qstrCompanyCode;
    }

    /************************************************
     * 函数名   : setInternalVersion
     * 输入参数 :
       const QString& qstrInternalVersion: 内部版本号
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 设置内部版本号
     ************************************************/
    void DataSpecification::setInternalVersion(const QString& qstrInternalVersion)
    {
        m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion = qstrInternalVersion;
    }

    /************************************************
     * 函数名   : getSpectrumDataFileHead
     * 输入参数 : NULL
     * 输出参数 :
       SpectrumDataFileHead& stSpectrumDataFileHead: 图谱数据文件头结构体
     * 返回值   : void
     * 功能     : 获取图谱数据文件头
     ************************************************/
    void DataSpecification::getSpectrumDataFileHead(SpectrumDataFileHead& stSpectrumDataFileHead)
    {
        stSpectrumDataFileHead.iFileLength = m_pDataSpecificationPrivate->m_stFileHead.iFileLength;
        stSpectrumDataFileHead.qstrVersion = m_pDataSpecificationPrivate->m_stFileHead.qstrVersion;
        stSpectrumDataFileHead.qstrGenerationTime = m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime;
        stSpectrumDataFileHead.qstrStationName = m_pDataSpecificationPrivate->m_stFileHead.qstrStationName;
        stSpectrumDataFileHead.qstrStationCode = m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode;
        stSpectrumDataFileHead.eWeather = static_cast<Weather>(m_pDataSpecificationPrivate->m_stFileHead.ucWeather);
        stSpectrumDataFileHead.fTemperature = m_pDataSpecificationPrivate->m_stFileHead.fTemperature;
        stSpectrumDataFileHead.cHumidity = m_pDataSpecificationPrivate->m_stFileHead.cHumidity;
        stSpectrumDataFileHead.qstrInstrumentManufacturer = m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer;
        stSpectrumDataFileHead.qstrInstrumentModel = m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel;
        stSpectrumDataFileHead.qstrInstrumentVersion = m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion;
        stSpectrumDataFileHead.qstrInstrumentSerialNumber = m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber;
        stSpectrumDataFileHead.fSystemFrequency = m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency;
        stSpectrumDataFileHead.sSpectrumCount = m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount;
        stSpectrumDataFileHead.qstrCompanyCode = m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode;
        stSpectrumDataFileHead.dataFileVersion = m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion;
    }

    /************************************************
     * 函数名   : saveAsBinary
     * 输入参数 :
       const QString& qstrFilePath: 保存的文件路径
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 保存成二进制文件
     ************************************************/
    bool DataSpecification::saveAsBinary(const QString& qstrFilePath)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::WriteOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }

        QByteArray qbaBinaryValue = encodeToBinary();
        file.write(qbaBinaryValue);
        file.close();

        return true;
    }

    /************************************************
     * 函数名   : saveAsXML
     * 输入参数 :
       const QString& qstrFilePath: 保存的文件路径
       const bool bCrypt: 是否加密
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 保存成XML文件
     ************************************************/
    bool DataSpecification::saveAsXML(const QString& qstrFilePath, const bool bCrypt /*= true*/)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::WriteOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }

        QByteArray qbaXMLValue = encodeToXML(bCrypt);
        file.write(qbaXMLValue);
        file.close();

        return true;
    }

    /************************************************
     * 函数名   : saveAsJSON
     * 输入参数 :
       const QString& qstrFilePath: 保存的文件路径
       const bool bCrypt: 是否加密
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 保存成JSON文件
     ************************************************/
    bool DataSpecification::saveAsJSON(const QString& qstrFilePath, const bool bCrypt /*= true*/)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::WriteOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }

        QByteArray qbaJSONValue = encodeToJSON(bCrypt);
        file.write(qbaJSONValue);
        file.close();

        return true;
    }

    /************************************************
     * 函数名   : parseBinaryFromFile
     * 输入参数 :
       const QString& qstrFilePath: 文件路径
       const bool bCrypt: 是否加密
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 从文件解析二进制数据
     ************************************************/
    bool DataSpecification::parseBinaryFromFile(const QString& qstrFilePath, const bool bCrypt /*= true*/)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::ReadOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }
        QByteArray qbaData = file.readAll();
        file.close();

        return parseBinaryData(qbaData, bCrypt);
    }

    /************************************************
     * 函数名   : parseXMLFromFile
     * 输入参数 :
       const QString& qstrFilePath: 保存的文件路径
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 从文件解析XML数据
     ************************************************/
    bool DataSpecification::parseXMLFromFile(const QString& qstrFilePath, const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::ReadOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }
        QByteArray qbaData = file.readAll();
        file.close();

        return parseXMLData(qbaData, bCrypt, eEncodeFormat);
    }

    /************************************************
     * 函数名   : parseJSONFromFile
     * 输入参数 :
       const QString& qstrFilePath: 保存的文件路径
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 从文件解析JSON数据
     ************************************************/
    bool DataSpecification::parseJSONFromFile(const QString& qstrFilePath, const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        QFile file(qstrFilePath);
        if (!file.open(QIODevice::ReadOnly))
        {
            qWarning(QString("Fail to open %1").arg(qstrFilePath).toLocal8Bit().data());
            return false;
        }
        QByteArray qbaData = file.readAll();
        file.close();

        return parseJSONData(qbaData, bCrypt, eEncodeFormat);
    }

    /************************************************
     * 函数名   : parseBinaryData
     * 输入参数 :
       const QByteArray& qbaData: 二进制数据
       const bool bCrypt: 是否加密
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析二进制数据
     ************************************************/
    bool DataSpecification::parseBinaryData(const QByteArray& qbaData, const bool bCrypt /*= true*/)
    {
        if (!checkBinaryCRC32(qbaData))
        {
            qWarning("DataSpecification::parseBinaryData check crc32 failed.");
            return false;
        }

        // 获取文件总长度
        int len = 0;
        if (qbaData.size() > (int)sizeof(int))
        {
            QDataStream in(qbaData);
            in.setByteOrder(QDataStream::LittleEndian);
            in >> len;
        }

        if (len < gs_iFileHeadLength + FILE_TAIL_LENTH || len != qbaData.length())
        {
            qWarning("DataSpecification::parseBinaryData parse failed, bytes length is %d, file length is %d", qbaData.length(), len);
            return false;
        }

        clearSpectrums();
        if (parseBinaryFileHead(QByteArray::fromRawData(qbaData.data(), gs_iFileHeadLength)))
        {
            m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.reserve(m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount);
            return parseBinarySpectrumsData(QByteArray::fromRawData(qbaData.data() + gs_iFileHeadLength, qbaData.length() - gs_iFileHeadLength - FILE_TAIL_LENTH));
        }

        return false;
    }

    /************************************************
     * 函数名   : parseXMLData
     * 输入参数 :
       const QByteArray& qbaData: 二进制数据
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析XML数据
     ************************************************/
    bool DataSpecification::parseXMLData(const QByteArray& qbaData, const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        QByteArray qbaXMLData = qbaData;
        if (bCrypt)
        {
            qbaXMLData = deCrypt(qbaXMLData);
        }

        const char* pchCodecName;
        if (eEncodeFormat == ENCODE_UTF8)
        {
            pchCodecName = "utf-8";
        }
        else if (eEncodeFormat == ENCODE_UTF16)
        {
            pchCodecName = "utf-16";
        }
        else
        {
            qWarning("wrong ecode format when open xml file!");
            return false;
        }
        XMLDocument doc(qbaXMLData, pchCodecName);

        clearSpectrums();
        //解析文件头部
        parseXMLFileHead(doc);
        m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.reserve(m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount);

        doc.beginElement(STR_FILE_NODE_NAME_SPECTRUMS);
        QList<QDomElement> mapElems = doc.childElement(STR_FILE_NODE_NAME_SPECTRUM);
        qWarning("mapElems.size() is %d\n", mapElems.size());
        //遍历解析map
        for (int i = 0; i < mapElems.size(); i++)
        {
            QDomElement elem = mapElems.at(i);
            //获取map根节点的tag，并创建对应对象实例
            QString strRootTag = elem.firstChildElement().tagName();
            qWarning() << "strRootTag:" << strRootTag;
            doc.beginElement(mapElems.at(i));

            Spectrum* pSpectrum = dynamic_cast<Spectrum*>(SpectrumFactory::createObject(strRootTag.toLatin1()));
            if (NULL != pSpectrum)
            {
                pSpectrum->setDataSpecificationVersion(m_eDataSpecificationVersion);
                pSpectrum->parseXMLData(doc);
                m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.push_back(pSpectrum);
            }
            doc.endElement();
        }

        doc.endElement();




        // TODO:目前QDomDocument读取XML内容再生成出来的XML和原有XML文件不一致，导致CRC32校验不通过，后续解决 [9/29/2019 hongcheng]
        //// 校验CRC32
        //if (!doc.hasElement(XML_FILE_NODE_NAME_CRC32))
        //{
        //    qWarning("DataFile::parseXMLFromFile check crc32 failed.");
        //    return false;
        //}

        //qDebug() << "DataFile::parseXMLFromFile 1: " << doc.getByteArray().size();
        //quint32 iCRC32 = doc.value(XML_FILE_NODE_NAME_CRC32).toUInt();
        //doc.removeElement(XML_FILE_NODE_NAME_CRC32);
        //quint32 iCalCRC32 = crc32(doc.getByteArray(), doc.getByteArray().size());
        //if (iCalCRC32 != iCRC32)
        //{
        //    qWarning("DataFile::parseXMLFromFile check crc32 failed.");
        //    return false;
        //}
        //qDebug("DataFile::parseXMLFromFile check crc32 success.");

        return true;
    }

    /************************************************
     * 函数名   : parseJSONData
     * 输入参数 :
       const QByteArray& qbaData: 二进制数据
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析JSON数据
     ************************************************/
    bool DataSpecification::parseJSONData(const QByteArray& qbaData, const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        QByteArray qbaJSONData = qbaData;
        if (bCrypt)
        {
            qbaJSONData = deCrypt(qbaJSONData);
        }

        rapidjson::Document doc;
        doc.Parse(qbaJSONData);

        // 校验CRC32
        if (!checkJSONCRC32(doc))
        {
            qWarning("DataSpecification::parseJSONData check crc32 failed.");
            return false;
        }

        rapidjson::Value value;
        if (!parseJSONDocument(doc, value))
        {
            return false;
        }

        clearSpectrums();
        //解析文件头部
        if (value.HasMember(STR_FILE_NODE_NAME_FILE_HEAD))
        {
            const rapidjson::Value& jsonFileHeadValue = value[STR_FILE_NODE_NAME_FILE_HEAD];
            parseJSONFileHead(jsonFileHeadValue);
        }
        m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.reserve(m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount);

        if (value.HasMember(STR_FILE_NODE_NAME_SPECTRUMS))
        {
            const rapidjson::Value& jsonSpectrumsData = value[STR_FILE_NODE_NAME_SPECTRUMS];
            parseJSONSpectrumsData(jsonSpectrumsData);
        }

        return true;
    }

    /************************************************
     * 函数名   : encodeToBinary
     * 输入参数 : NULL
     * 输出参数 : NULL
     * 返回值   : QByteArray
     * 功能     : 将数据组织成二进制形式
     ************************************************/
    QByteArray DataSpecification::encodeToBinary()
    {
        QByteArray baBinaryValue;
        saveBinaryFileHead(baBinaryValue);

        QDataStream out(&baBinaryValue, QIODevice::ReadWrite);
        out.setByteOrder(QDataStream::LittleEndian);
        out.setFloatingPointPrecision(QDataStream::SinglePrecision);
        out.device()->seek(out.device()->size()); // pos:512

        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (Q_NULLPTR != pSpectrum)
            {
                QByteArray qbaSpectrum;
                pSpectrum->saveAsBinary(qbaSpectrum);
                baBinaryValue.append(qbaSpectrum);
            }
        }

        saveBinaryFileTail(baBinaryValue);

        return baBinaryValue;
    }

    /************************************************
     * 函数名   : encodeToXML
     * 输入参数 :
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : QByteArray
     * 功能     : 将数据组织成xml形式
     ************************************************/
    QByteArray DataSpecification::encodeToXML(const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        const char* pchCodecName;
        if (eEncodeFormat == ENCODE_UTF8)
        {
            pchCodecName = "utf-8";
        }
        else if (eEncodeFormat == ENCODE_UTF16)
        {
            pchCodecName = "utf-16";
        }
        else
        {
            qWarning("DataSpecification::encodeToXML createXMLFile failed!");
            return "";
        }

        XMLDocument xmlDocumentObj(STR_FILE_ROOT_NODE_NAME, pchCodecName);

        // 保存头部
        saveXMLFileHead(xmlDocumentObj);

        // 保存图谱数据
        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (NULL != pSpectrum)
            {
                pSpectrum->saveAsXML(xmlDocumentObj);
            }
        }

        // 保存CRC32
        quint32 iCRC32 = CRCUtil::getCRC32(xmlDocumentObj.getByteArray(), xmlDocumentObj.getByteArray().size());
        QDomElement root = xmlDocumentObj.documentElement();
        xmlDocumentObj.beginElement(root);
        xmlDocumentObj.setValue(STR_FILE_NODE_NAME_CRC32, QString::number(iCRC32));
        xmlDocumentObj.endElement();

        QByteArray baXMLValue = xmlDocumentObj.getByteArray();

        if (bCrypt)
        {
            baXMLValue = enCrypt(baXMLValue);
        }

        return baXMLValue;
    }

    /************************************************
     * 函数名   : encodeToJSON
     * 输入参数 :
       const bool bCrypt: 是否加密
       const EncodeFormat eEncodeFormat: 编码格式
     * 输出参数 : NULL
     * 返回值   : QByteArray
     * 功能     : 将数据组织成JSON形式
     ************************************************/
    QByteArray DataSpecification::encodeToJSON(const bool bCrypt /*= true*/, const EncodeFormat eEncodeFormat /*= ENCODE_UTF8*/)
    {
        rapidjson::Document doc;
        rapidjson::Value value;
        rapidjson::Document::AllocatorType& alloc = doc.GetAllocator();
        value.SetObject();

        // 保存头部
        rapidjson::Value jsonFileHeadValue;
        jsonFileHeadValue.SetObject();
        saveJSONFileHead(alloc, jsonFileHeadValue);
        value.AddMember(rapidjson::Value(STR_FILE_NODE_NAME_FILE_HEAD, alloc), jsonFileHeadValue.Move(), alloc);

        // 保存图谱数据
        rapidjson::Value spectrumsJsonValue;
        spectrumsJsonValue.SetArray();
        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (NULL != pSpectrum)
            {
                rapidjson::Value wrap;
                wrap.SetObject();

                rapidjson::Value temp;
                pSpectrum->saveAsJSON(alloc, temp);

                rapidjson::Value key(pSpectrum->spectrumName().toStdString().c_str(), alloc);
                wrap.AddMember(key, temp.Move(), alloc);

                spectrumsJsonValue.PushBack(wrap.Move(), alloc);
            }
        }
        value.AddMember(rapidjson::Value(STR_FILE_NODE_NAME_SPECTRUMS, alloc), spectrumsJsonValue.Move(), alloc);

        std::string strJsonValue;
        saveJSONDocument(value, doc);
        saveJSON <true>(doc, strJsonValue);

        // 保存CRC32校验码
        QByteArray baJSONValueTmp(strJsonValue.c_str());
        quint32 iCRC32 = CRCUtil::getCRC32(baJSONValueTmp.data(), baJSONValueTmp.size());

        rapidjson::Value key(STR_FILE_NODE_NAME_CRC32, alloc);
        doc.AddMember(key, iCRC32, alloc);

        // 保存完整的json字符串
        saveJSON <true>(doc, strJsonValue);
        QByteArray baJSONValue(strJsonValue.c_str());

        if (bCrypt)
        {
            baJSONValue = enCrypt(baJSONValue);
        }

        return baJSONValue;
    }

    /************************************************
     * 函数名   : saveBinaryFileHead
     * 输入参数 :
       QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 保存二进制文件头部
     ************************************************/
    void DataSpecification::saveBinaryFileHead(QByteArray& qbaPackage)
    {
        QDataStream out(&qbaPackage, QIODevice::ReadWrite);
        out.setByteOrder(QDataStream::LittleEndian);
        out.setFloatingPointPrecision(QDataStream::SinglePrecision);

        // 文件长度预留
        out << qint32(0);

        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrVersion, DataSpecificationGW::TYPE_VERSION, out, VERSON_STR_LENGTH);
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime, DataSpecificationGW::TYPE_DATETIME, out, DATETIME_STR_LENGTH);

        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrStationName, DataSpecificationGW::TYPE_UNICODE, out, UNICODE_STR_LENGTH);
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode, DataSpecificationGW::TYPE_ASCII, out, ASCII_STR_LENGTH);

        out << m_pDataSpecificationPrivate->m_stFileHead.ucWeather;
        out << m_pDataSpecificationPrivate->m_stFileHead.fTemperature;
        out << m_pDataSpecificationPrivate->m_stFileHead.cHumidity;
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer, DataSpecificationGW::TYPE_UNICODE, out, 32);
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel, DataSpecificationGW::TYPE_UNICODE, out, 32);
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion, DataSpecificationGW::TYPE_VERSION, out, VERSON_STR_LENGTH);
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber, DataSpecificationGW::TYPE_ASCII, out, 32);

        out << m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency;
        out << m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount;
        qDebug() << "DataFile::saveAsBinary spectrumCount: " << m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount;

        DataSpecificationUtils::saveBinaryReservedData(FILE_HEAD_RESERVE, out);

        // 公司代码
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode, DataSpecificationGW::TYPE_VERSION, out, 2);

        // 内部数据规范版本号
        DataSpecificationUtils::convertStringToBinary(m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion, DataSpecificationGW::TYPE_VERSION, out, VERSON_STR_LENGTH);
    }

    /************************************************
     * 函数名   : saveXMLFileHead
     * 输入参数 :
       XMLDocument& xmlDocumentObj: xml文档对象
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 保存XML文件头部
     ************************************************/
    void DataSpecification::saveXMLFileHead(XMLDocument& xmlDocumentObj)
    {
        QDomElement root = xmlDocumentObj.documentElement();
        xmlDocumentObj.beginElement(root);
        xmlDocumentObj.beginElement(STR_FILE_NODE_NAME_FILE_HEAD);

        xmlDocumentObj.setValue(STR_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrVersion);
        xmlDocumentObj.setValue(STR_GENERATION_TIME, QString::number(DataSpecificationUtils::serializeDateTime(m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime)));
        xmlDocumentObj.setValue(STR_SUBSTATION_NAME, m_pDataSpecificationPrivate->m_stFileHead.qstrStationName);
        xmlDocumentObj.setValue(STR_SUBSTATION_CODE, m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode);
        xmlDocumentObj.setValue(STR_WEATHER, QString::number(m_pDataSpecificationPrivate->m_stFileHead.ucWeather));
        xmlDocumentObj.setValue(STR_TEMPERATURE, QString::number(m_pDataSpecificationPrivate->m_stFileHead.fTemperature, 'f', 1));
        xmlDocumentObj.setValue(STR_HUMIDITY, QString::number(m_pDataSpecificationPrivate->m_stFileHead.cHumidity));
        xmlDocumentObj.setValue(STR_MANUFACTURER, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer);
        xmlDocumentObj.setValue(STR_INSTRUMENT_MODEL, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel);
        xmlDocumentObj.setValue(STR_INSTRUMENT_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion);
        xmlDocumentObj.setValue(STR_INSTRUMENT_SN, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber);
        xmlDocumentObj.setValue(STR_SYS_FREQUENCY, QString::number(m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency, 'f', 1));
        xmlDocumentObj.setValue(STR_SPECTRUM_COUNT, QString::number(m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount));
        xmlDocumentObj.setValue(STR_COMPANY_CODE, m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode);
        xmlDocumentObj.setValue(STR_DATA_FILE_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion);
        xmlDocumentObj.endElement();
    }

    /************************************************
     * 函数名   : saveJSONFileHead
     * 输入参数 : NULL
     * 输出参数 :
       rapidjson::Document& jsonDoc: json文档对象
       rapidjson::Value& jsonValue: json数据
     * 返回值   : void
     * 功能     : 保存JSON文件头部
     ************************************************/
    void DataSpecification::saveJSONFileHead(rapidjson::Document::AllocatorType& alloc, rapidjson::Value& jsonValue)
    {
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipVersion) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrVersion, STR_VERSION, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipGenerationTime) saveJSONField(QString::number(DataSpecificationUtils::serializeDateTime(m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime)), STR_GENERATION_TIME, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipStationName) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrStationName, STR_SUBSTATION_NAME, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipStationCode) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode, STR_SUBSTATION_CODE, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipWeather) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.ucWeather, STR_WEATHER, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipTemperature) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.fTemperature, STR_TEMPERATURE, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipHumidity) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.cHumidity, STR_HUMIDITY, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentManufacturer) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer, STR_MANUFACTURER, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentModel) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel, STR_INSTRUMENT_MODEL, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentVersion) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion, STR_INSTRUMENT_VERSION, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentSerialNumber) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber, STR_INSTRUMENT_SN, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipSystemFrequency) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency, STR_SYS_FREQUENCY, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipSpectrumCount) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount, STR_SPECTRUM_COUNT, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipCompanyCode) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode, STR_COMPANY_CODE, alloc, jsonValue);
        if (!m_pDataSpecificationPrivate->m_stFileHead.bSkipInternalVersion) saveJSONField(m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion, STR_DATA_FILE_VERSION, alloc, jsonValue);
    }

    /************************************************
     * 函数名   : saveBinaryFileTail
     * 输入参数 :
       QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 保存二进制文件尾部
     ************************************************/
    void DataSpecification::saveBinaryFileTail(QByteArray& qbaPackage)
    {
        QDataStream out(&qbaPackage, QIODevice::ReadWrite);
        out.setByteOrder(QDataStream::LittleEndian);
        out.setFloatingPointPrecision(QDataStream::SinglePrecision);
        qint32 iSize = out.device()->size();
        out.device()->seek(iSize);

        DataSpecificationUtils::saveBinaryReservedData(DATA_FILE_TAIL_RESERVED_BYTES_CNT, out);

        updateBinaryFileLength(qbaPackage);

        QDataStream outWithCRC(&qbaPackage, QIODevice::ReadWrite);
        outWithCRC.setByteOrder(QDataStream::LittleEndian);
        qint32 iCRC32 = CRCUtil::getCRC32(qbaPackage.constData(), qbaPackage.size());
        qint32 iSizeWithCRC = outWithCRC.device()->size();
        outWithCRC.device()->seek(iSizeWithCRC);
        outWithCRC << (qint32)iCRC32;
    }

    /************************************************
     * 函数名   : updateBinaryFileLength
     * 输入参数 :
       QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : void
     * 功能     : 更新二进制文件长度
     ************************************************/
    void DataSpecification::updateBinaryFileLength(QByteArray& qbaPackage)
    {
        QDataStream out(&qbaPackage, QIODevice::ReadWrite);
        out.setByteOrder(QDataStream::LittleEndian);
        out.setFloatingPointPrecision(QDataStream::SinglePrecision);
        int iCRC32Size = sizeof(qint32);
        qint32 iSizeWithoutCRC = out.device()->size();
        m_pDataSpecificationPrivate->m_stFileHead.iFileLength = iSizeWithoutCRC + iCRC32Size;
        out.device()->seek(0);
        out << m_pDataSpecificationPrivate->m_stFileHead.iFileLength;
    }

    /************************************************
     * 函数名   : parseBinaryFileHead
     * 输入参数 :
       const QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析二进制文件头部
     ************************************************/
    bool DataSpecification::parseBinaryFileHead(const QByteArray& qbaPackage)
    {
        QDataStream in(qbaPackage);
        in.setByteOrder(QDataStream::LittleEndian);
        in.setFloatingPointPrecision(QDataStream::SinglePrecision);

        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipFileLength, m_pDataSpecificationPrivate->m_stFileHead.iFileLength, m_pDataSpecificationPrivate->m_stFileHead.bHasFileLength);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipVersion, DataSpecificationGW::TYPE_VERSION, VERSON_STR_LENGTH, m_pDataSpecificationPrivate->m_stFileHead.qstrVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasVersion);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipGenerationTime, DataSpecificationGW::TYPE_DATETIME, DATETIME_STR_LENGTH, m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime, m_pDataSpecificationPrivate->m_stFileHead.bHasGenerationTime);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipStationName, DataSpecificationGW::TYPE_UNICODE, UNICODE_STR_LENGTH, m_pDataSpecificationPrivate->m_stFileHead.qstrStationName, m_pDataSpecificationPrivate->m_stFileHead.bHasStationName);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipStationCode, DataSpecificationGW::TYPE_ASCII, 32, m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode, m_pDataSpecificationPrivate->m_stFileHead.bHasStationCode);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipWeather, m_pDataSpecificationPrivate->m_stFileHead.ucWeather, m_pDataSpecificationPrivate->m_stFileHead.bHasWeather);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipTemperature, m_pDataSpecificationPrivate->m_stFileHead.fTemperature, m_pDataSpecificationPrivate->m_stFileHead.bHasTemperature);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipHumidity, m_pDataSpecificationPrivate->m_stFileHead.cHumidity, m_pDataSpecificationPrivate->m_stFileHead.bHasHumidity);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentManufacturer, DataSpecificationGW::TYPE_UNICODE, 32, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentManufacturer);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentModel, DataSpecificationGW::TYPE_UNICODE, 32, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentModel);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentVersion, DataSpecificationGW::TYPE_VERSION, VERSON_STR_LENGTH, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentVersion);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipInstrumentSerialNumber, DataSpecificationGW::TYPE_ASCII, 32, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentManufacturer);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipSystemFrequency, m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency, m_pDataSpecificationPrivate->m_stFileHead.bHasSystemFrequency);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipSpectrumCount, m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount, m_pDataSpecificationPrivate->m_stFileHead.bHasSpectrumCount);

        if (FILE_HEAD_RESERVE != in.skipRawData(FILE_HEAD_RESERVE))
        {
            qDebug() << "DataSpecification::parseBinaryFileHead skipRawData failed";
            return false;
        }

        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipCompanyCode, DataSpecificationGW::TYPE_VERSION, 2, m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode, m_pDataSpecificationPrivate->m_stFileHead.bHasCompanyCode);
        parseBinaryField(in, m_pDataSpecificationPrivate->m_stFileHead.bSkipInternalVersion, DataSpecificationGW::TYPE_VERSION, VERSON_STR_LENGTH, m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasInternalVersion);

        return in.status() == QDataStream::Ok;
    }

    /************************************************
     * 函数名   : parseXMLFileHead
     * 输入参数 :
       XMLDocument& xmlDocumentObj: xml文档对象
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析XML文件头部
     ************************************************/
    bool DataSpecification::parseXMLFileHead(XMLDocument& xmlDocumentObj)
    {
        xmlDocumentObj.beginElement(STR_FILE_NODE_NAME_FILE_HEAD);

        m_pDataSpecificationPrivate->m_stFileHead.qstrVersion = xmlDocumentObj.value(STR_VERSION);
        m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime = xmlDocumentObj.value(STR_GENERATION_TIME);
        m_pDataSpecificationPrivate->m_stFileHead.qstrStationName = xmlDocumentObj.value(STR_SUBSTATION_NAME);
        m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode = xmlDocumentObj.value(STR_SUBSTATION_CODE);
        m_pDataSpecificationPrivate->m_stFileHead.ucWeather = xmlDocumentObj.value(STR_WEATHER).toUInt();
        m_pDataSpecificationPrivate->m_stFileHead.fTemperature = xmlDocumentObj.value(STR_TEMPERATURE).toFloat();
        m_pDataSpecificationPrivate->m_stFileHead.cHumidity = xmlDocumentObj.value(STR_HUMIDITY).toInt();
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer = xmlDocumentObj.value(STR_MANUFACTURER);
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel = xmlDocumentObj.value(STR_INSTRUMENT_MODEL);
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber = xmlDocumentObj.value(STR_INSTRUMENT_SN);
        m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion = xmlDocumentObj.value(STR_INSTRUMENT_VERSION);
        m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency = xmlDocumentObj.value(STR_SYS_FREQUENCY).toFloat();
        m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount = xmlDocumentObj.value(STR_SPECTRUM_COUNT).toInt();
        m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode = xmlDocumentObj.value(STR_COMPANY_CODE);
        m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion = xmlDocumentObj.value(STR_DATA_FILE_VERSION);

        xmlDocumentObj.endElement();

        return true;
    }

    /************************************************
     * 函数名   : parseJSONFileHead
     * 输入参数 :
       const rapidjson::Value& jsonValue: json数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析JSON文件头部
     ************************************************/
    bool DataSpecification::parseJSONFileHead(const rapidjson::Value& jsonValue)
    {
        parseJSONField(jsonValue, STR_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasVersion);
        parseJSONField(jsonValue, STR_GENERATION_TIME, m_pDataSpecificationPrivate->m_stFileHead.qstrGenerationTime, m_pDataSpecificationPrivate->m_stFileHead.bHasGenerationTime);
        parseJSONField(jsonValue, STR_SUBSTATION_NAME, m_pDataSpecificationPrivate->m_stFileHead.qstrStationName, m_pDataSpecificationPrivate->m_stFileHead.bHasStationName);
        parseJSONField(jsonValue, STR_SUBSTATION_CODE, m_pDataSpecificationPrivate->m_stFileHead.qstrStationCode, m_pDataSpecificationPrivate->m_stFileHead.bHasStationCode);
        parseJSONField(jsonValue, STR_WEATHER, m_pDataSpecificationPrivate->m_stFileHead.ucWeather, m_pDataSpecificationPrivate->m_stFileHead.bHasWeather);
        parseJSONField(jsonValue, STR_TEMPERATURE, m_pDataSpecificationPrivate->m_stFileHead.fTemperature, m_pDataSpecificationPrivate->m_stFileHead.bHasTemperature);
        parseJSONField(jsonValue, STR_HUMIDITY, m_pDataSpecificationPrivate->m_stFileHead.cHumidity, m_pDataSpecificationPrivate->m_stFileHead.bHasHumidity);
        parseJSONField(jsonValue, STR_MANUFACTURER, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentManufacturer, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentManufacturer);
        parseJSONField(jsonValue, STR_INSTRUMENT_MODEL, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentModel, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentModel);
        parseJSONField(jsonValue, STR_INSTRUMENT_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentVersion);
        parseJSONField(jsonValue, STR_INSTRUMENT_SN, m_pDataSpecificationPrivate->m_stFileHead.qstrInstrumentSerialNumber, m_pDataSpecificationPrivate->m_stFileHead.bHasInstrumentManufacturer);
        parseJSONField(jsonValue, STR_SYS_FREQUENCY, m_pDataSpecificationPrivate->m_stFileHead.fSystemFrequency, m_pDataSpecificationPrivate->m_stFileHead.bHasSystemFrequency);
        parseJSONField(jsonValue, STR_SPECTRUM_COUNT, m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount, m_pDataSpecificationPrivate->m_stFileHead.bHasSpectrumCount);
        parseJSONField(jsonValue, STR_COMPANY_CODE, m_pDataSpecificationPrivate->m_stFileHead.qstrCompanyCode, m_pDataSpecificationPrivate->m_stFileHead.bHasCompanyCode);
        parseJSONField(jsonValue, STR_DATA_FILE_VERSION, m_pDataSpecificationPrivate->m_stFileHead.qstrInternalVersion, m_pDataSpecificationPrivate->m_stFileHead.bHasInternalVersion);

        return true;
    }

    /************************************************
     * 函数名   : parseBinarySpectrumsData
     * 输入参数 :
       const QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析二进制文件图谱数据
     ************************************************/
    bool DataSpecification::parseBinarySpectrumsData(const QByteArray& qbaPackage)
    {
        QDataStream in(qbaPackage);
        in.setByteOrder(QDataStream::LittleEndian);
        in.setFloatingPointPrecision(QDataStream::SinglePrecision);

        int lengthToParse = qbaPackage.length();
        const char* pData = qbaPackage.data();

        quint8 chartType = 0;
        qint32 chartLength = 0;
        while (lengthToParse > 0)
        {
            in >> chartType;        //图谱类型编码
            in >> chartLength;      //图谱数据长度


            if (in.status() != QDataStream::Ok)
            {
                qWarning("DataSpecification::parseBinarySpectrumsData failed.");
                return false;
            }

            QString strClassName = DataSpecificationUtils::spectrumTypeCodeEnum2QString(SpectrumTypeCode(chartType));

            Spectrum* pSpectrum = dynamic_cast<Spectrum*>(SpectrumFactory::createObject(strClassName.toLatin1()));

            if (NULL != pSpectrum)
            {
                pSpectrum->setDataSpecificationVersion(m_eDataSpecificationVersion);
                m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.push_back(pSpectrum);

                bool parseRes = pSpectrum->parseBinaryData(QByteArray::fromRawData(pData, chartLength));
            }
            else
            {
                qWarning("Fail to create spectrum %d.", chartType);
            }

            pData += chartLength;
            lengthToParse -= chartLength;
            in.skipRawData(chartLength - sizeof(chartLength) - sizeof(chartType));
        }

        return true;
    }

    /************************************************
     * 函数名   : parseJSONSpectrumsData
     * 输入参数 :
       const rapidjson::Value& jsonValue: json数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 解析JSON文件图谱数据
     ************************************************/
    bool DataSpecification::parseJSONSpectrumsData(const rapidjson::Value& jsonValue)
    {
        if (!jsonValue.IsArray())
        {
            return false;
        }
        rapidjson::SizeType size = jsonValue.Size();
        m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.reserve(size);

        for (rapidjson::SizeType i = 0; i < size; ++i)
        {
            for (rapidjson::Value::ConstMemberIterator itr = jsonValue[i].MemberBegin();
                itr != jsonValue[i].MemberEnd(); ++itr)
            {
                qDebug() << "DataSpecification::parseJSONSpectrumsData: name " << itr->name.GetString();
                Spectrum* pSpectrum = dynamic_cast<Spectrum*>(SpectrumFactory::createObject(itr->name.GetString()));
                pSpectrum->setDataSpecificationVersion(m_eDataSpecificationVersion);
                if (!pSpectrum->parseJSONData(itr->value))
                {
                    continue;
                }
                m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.push_back(pSpectrum);
            }
        }
    }

    /************************************************
     * 函数名   : checkBinaryCRC32
     * 输入参数 :
       const QByteArray& qbaPackage: 数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 校验二进制数据
     ************************************************/
    bool DataSpecification::checkBinaryCRC32(const QByteArray& qbaPackage)
    {
        int iCRC32Size = sizeof(qint32);
        quint32 iCRC32 = CRCUtil::getCRC32(qbaPackage.data(), qbaPackage.size() - iCRC32Size);
        quint32 fileCRC = 0;

        QDataStream in(qbaPackage);
        in.setByteOrder(QDataStream::LittleEndian);
        in.skipRawData(qbaPackage.length() - iCRC32Size);

        in >> fileCRC;

        return (fileCRC == iCRC32);
    }

    /************************************************
     * 函数名   : checkJSONCRC32
     * 输入参数 :
       rapidjson::Document& doc: 数据
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 校验JSON数据
     ************************************************/
    bool DataSpecification::checkJSONCRC32(rapidjson::Document& doc)
    {
        if (!doc.HasMember(STR_FILE_NODE_NAME_CRC32))
        {
            qWarning("DataSpecification::checkJSONCRC32 1.");
            return false;
        }

        quint32 iCRC32 = doc[STR_FILE_NODE_NAME_CRC32].GetUint();
        if (!doc.RemoveMember(STR_FILE_NODE_NAME_CRC32))
        {
            qWarning("DataSpecification::checkJSONCRC32 2.");
            return false;
        }

        std::string strJsonValue;
        saveJSON <true>(doc, strJsonValue);
        quint32 iCalCRC32 = CRCUtil::getCRC32(strJsonValue.c_str(), strJsonValue.size());
        if (iCalCRC32 != iCRC32)
        {
            qWarning("DataSpecification::checkJSONCRC32 3.");
            return false;
        }
        qDebug("DataSpecification::parseJSONData check crc32 success.");
    }

    /************************************************
     * 函数名   : clearSpectrums
     * 输入参数 : NULL
     * 输出参数 : NULL
     * 返回值   : bool
     * 功能     : 清除图谱对象
     ************************************************/
    void DataSpecification::clearSpectrums()
    {
        for (Spectrum* pSpectrum : m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum)
        {
            if (NULL != pSpectrum)
            {
                delete pSpectrum;
                pSpectrum = NULL;
            }
        }
        m_pDataSpecificationPrivate->m_stSpectrums.vecSpectrum.clear();
        m_pDataSpecificationPrivate->m_stFileHead.sSpectrumCount = 0;
    }

}
